using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.IO;
using System.Xml;
using System.Threading;
using System.Collections;
using System.Configuration;
using System.Windows.Forms;
using PSLib = Microsoft.Office.Project.Server.Library;

namespace Microsoft.ProjectServer.QueueWatch
{
    public partial class MainForm : Form
    {
        #region Private Data
        private Queue q = new Queue();
        private XmlDocument xmlConfig = new XmlDocument();
        #endregion

        public MainForm()
        {
            InitializeComponent();
        }

        #region UI Control Event Handlers
        private void btnLogin_Click(object sender, EventArgs e)
        {
            try
            {
                Cursor = Cursors.WaitCursor;

                if (btnLogin.Text == "Login")
                {
                    if (chkNTAuth.Checked)
                    {
                        q.Login(txtURL.Text);
                        WriteLog("Logged in using NT authentication");
                    }
                    else
                    {
                        q.Login(txtURL.Text, txtUser.Text, txtPassword.Text);
                        WriteLog("Logged in using forms authentication");
                    }
                    RetrieveQueueInfo();

                    timer1.Enabled = true;
                    btnLogin.Text = "Logoff";
                    txtURL.Enabled = false;
                    chkNTAuth.Enabled = false;
                }
                else
                {
                    q.Logoff();
                    timer1.Enabled = false;
                    btnLogin.Text = "Login";
                    txtURL.Enabled = true;
                    chkNTAuth.Enabled = true;
                    WriteLog("Logged off");
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
                WriteLog(ex.Message);
            }
            finally
            {
                Cursor = Cursors.Default;
            }
        }

        private void chkNTAuth_CheckedChanged(object sender, EventArgs e)
        {
            grpFormsAuth.Enabled = !chkNTAuth.Checked;
        }
        #endregion

        #region Menu Handlers
        private void closeToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Close();
        }

        private void pollingToolStripMenuItem_Click(object sender, EventArgs e)
        {
            try
            {
                timer1.Enabled = false;

                Polling dlg = new Polling();
                dlg.Interval = timer1.Interval;
                if (dlg.ShowDialog() == DialogResult.OK)
                {
                    timer1.Interval = dlg.Interval;
                }

                timer1.Enabled = true;
            }
            catch (Exception ex)
            {
                WriteLog(ex.Message);
                MessageBox.Show(ex.Message);
            }
        }

        private void optionsToolStripMenuItem_Click(object sender, EventArgs e)
        {
            try
            {
                timer1.Enabled = false;

                Options dlg = new Options();
                dlg.DataGrid = dgQueue;
                dlg.ShowDialog();
                dgQueue.Sort(dgQueue.Columns["SortOrder"], ListSortDirection.Ascending);

                timer1.Enabled = true;
            }
            catch (Exception ex)
            {
                WriteLog(ex.Message);
                MessageBox.Show(ex.Message);
            }
        }
        #endregion

        #region Form Methods
        private void Form1_Load(object sender, EventArgs e)
        {
            try
            {
                Splash formSplash = new Splash();
                formSplash.Show();
                Application.DoEvents();

                ConfigureGrid();
                LoadConfig();
                dgQueue.Sort(dgQueue.Columns["SortOrder"], ListSortDirection.Ascending);

                formSplash.FadeForm();
                formSplash.Close();
            }
            catch (Exception ex)
            {
                WriteLog(ex.Message);
                MessageBox.Show(ex.Message);
            }
        }

        private void MainForm_SizeChanged(object sender, EventArgs e)
        {
            try
            {
                dgQueue.Width = ClientRectangle.Width - (dgQueue.Location.X * 2);
                dgQueue.Height = ClientRectangle.Height - (dgQueue.Location.Y + dgQueue.Location.X);
                lbStatus.Width = ClientRectangle.Width - (lbStatus.Location.X + gbLogin.Location.X);
            }
            catch (Exception ex)
            {
                WriteLog(ex.Message);
                MessageBox.Show(ex.Message);
            }
        }

        private void timer1_Tick(object sender, EventArgs e)
        {
            try
            {
                if (q == null) return;
                timer1.Enabled = false;

                txtPolled.Text = DateTime.Now.ToShortDateString() + " " + DateTime.Now.ToLongTimeString();
                WriteLog("Updated " + txtPolled.Text);

                Thread updateThread = new Thread(new ThreadStart(RetrieveQueueInfo));
                updateThread.Start();

                timer1.Enabled = true;
            }
            catch (Exception ex)
            {
                WriteLog(ex.Message);
                MessageBox.Show(ex.Message);
            }
        }

        private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
        {
            SaveConfig();
        }
        #endregion

        #region Helper Methods
        private void RetrieveQueueInfo()
        {
            try
            {
                q.GetJobs();
            }
            catch
            {
                WriteLog("GetJobs failed.");
                return;
            }

            int numJobs = 0;
            int prevNumJobs = 0;
            int index;
            int diff;
            string queueType;
            string jobState;
            string temp;
            foreach (DataGridViewRow dr in dgQueue.Rows)
            {
                if (!dr.Visible) continue;

                queueType = dr.Cells["MessageType"].Value.ToString();
                foreach (DataGridViewColumn dc in dgQueue.Columns)
                {
                    if (!dc.Visible) continue;

                    jobState = dc.Name;
                    if (jobState == "MessageType") continue;

                    temp = dr.Cells[jobState].Value.ToString();
                    index = temp.IndexOf("(");
                    if (index > -1)
                    {
                        temp = temp.Substring(0, index);
                    }
                    prevNumJobs = Convert.ToInt32(temp);

                    numJobs = q.NumMessages((PSLib.QueueConstants.QueueMsgType)Enum.Parse(typeof(PSLib.QueueConstants.QueueMsgType), queueType),
                                            (PSLib.QueueConstants.JobState)Enum.Parse(typeof(PSLib.QueueConstants.JobState), jobState));

                    temp = numJobs.ToString();
                    diff = numJobs - prevNumJobs;
                    // If the number has changed, display in red with difference.
                    if (diff != 0)
                    {
                        temp = temp + "  (" + diff.ToString() + ")";
                        dr.Cells[jobState].Style.ForeColor = Color.Red;
                    }
                    else
                    {
                        dr.Cells[jobState].Style.ForeColor = Color.Black;
                    }
                    dr.Cells[jobState].Value = temp;
                }
            }
        }

        private void WriteLog(string Msg)
        {
            lbStatus.Items.Insert(0, DateTime.Now.ToShortDateString() + " " + DateTime.Now.ToShortTimeString() + " - " + Msg);
            if (lbStatus.Items.Count > 100) lbStatus.Items.RemoveAt(lbStatus.Items.Count - 1);
        }

        private bool IsCommonMessage(string name)
        {
            if (name.Length >= 5 && name.Substring(0, 5) == "Timer") return false;
            if (name.Length >= 3 && name.Substring(0, 3) == "CBS") return false;
            if (name.Length >= 12 && name.Substring(0, 12) == "RulesProcess") return false;
            if (name.Length >= 7 && name.Substring(0, 7) == "Restore") return false;
            if (name.Length >= 9 && name.Substring(0, 9) == "Reporting") return false;
            if (name.Length >= 7 && name.Substring(0, 7) == "Archive") return false;
            if (name.Length >= 4 && name.Substring(0, 4) == "Bump") return false;
            if (name == "Unknown") return false;
            if (name == "LastMessage") return false;
            return true;
        }

        private void ConfigureGrid()
        {
            int rowNum;
            int index = 0;
            foreach (string name in Enum.GetNames(typeof(PSLib.QueueConstants.QueueMsgType)))
            {
                rowNum = dgQueue.Rows.Add();
                foreach (DataGridViewCell dc in dgQueue.Rows[rowNum].Cells)
                {
                    // Skip the sort order and message type.
                    if (dc.ColumnIndex == 0 || dc.ColumnIndex == 1) continue;
                    // Set default for everything else.
                    dc.Value = 0;
                }

                dgQueue.Rows[rowNum].Cells["MessageType"].Value = name;
                dgQueue.Rows[rowNum].Visible = IsCommonMessage(name);
                if (dgQueue.Rows[rowNum].Visible) dgQueue.Rows[rowNum].Cells["SortOrder"].Value = index++;
            }
        }

        private void LoadConfig()
        {
            txtURL.Text = Properties.Settings.Default.ProjectServerURL;
            chkNTAuth.Checked = Properties.Settings.Default.NTAuth;
            txtUser.Text = Properties.Settings.Default.FormsUser;
            txtPassword.Text = Properties.Settings.Default.FormsPassword;
            timer1.Interval = Convert.ToInt32(Properties.Settings.Default.Interval);
            string jobStates = Properties.Settings.Default.JobStateList;
            string msgTypes = Properties.Settings.Default.MsgTypeList;
            if (jobStates.Length > 0 && msgTypes.Length > 0)
            {
                foreach (DataGridViewColumn dc in dgQueue.Columns)
                {
                    if (dc.Name == "MessageType" || dc.Name == "SortOrder") continue;

                    dc.Visible = jobStates.IndexOf(dc.Name) > -1;
                }
                char[] seperator = new char[1];
                seperator[0] = ',';
                string[] list = jobStates.Split(seperator);
                string[] token;
                for (int index = 0; index < list.GetLength(0); index++)
                {
                    seperator[0] = ':';
                    token = list[index].Split(seperator);
                    dgQueue.Columns[token[0]].DisplayIndex = Convert.ToInt32(token[1]);
                }

                // Display and hide rows as selected.
                seperator[0] = ',';
                list = msgTypes.Split(seperator);
                foreach (DataGridViewRow dr in dgQueue.Rows)
                {
                    dr.Visible = msgTypes.IndexOf(dr.Cells["MessageType"].Value.ToString()) > -1;
                    dr.Cells["SortOrder"].Value = GetMsgTypeSortOrder(list, dr.Cells["MessageType"].Value.ToString());
                }
            }
        }

        private int GetMsgTypeSortOrder(string[] list, string name)
        {
            char[] seperator = new char[1];
            string[] token;
            for (int index = 0; index < list.GetLength(0); index++)
            {
                seperator[0] = ':';
                token = list[index].Split(seperator);
                if (token[0] == name) return Convert.ToInt32(token[1]);
            }
            return -1;
        }

        private void SaveConfig()
        {
            string configFile = Application.ExecutablePath +  ".config";
            xmlConfig.Load(configFile);
            XmlNode nodeRoot = xmlConfig.SelectSingleNode("configuration/applicationSettings/Microsoft.ProjectServer.QueueWatch.Properties.Settings");
            if (nodeRoot == null) return;

            // Save data.
            XmlNodeList settings = nodeRoot.SelectNodes("setting");
            XmlNode nodeValue;
            string list;
            foreach (XmlNode setting in settings)
            {
                nodeValue = setting.SelectSingleNode("value");
                switch (setting.Attributes[0].Value)
                {
                    case "ProjectServerURL":
                        nodeValue.InnerXml = txtURL.Text;
                        break;

                    case "NTAuth":
                        nodeValue.InnerXml = chkNTAuth.Checked.ToString();
                        break;

                    case "FormsUser":
                        nodeValue.InnerXml = txtUser.Text;
                        break;

                    case "FormsPassword":
                        nodeValue.InnerXml = txtPassword.Text;
                        break;

                    case "Interval":
                        nodeValue.InnerXml = timer1.Interval.ToString();
                        break;

                    case "JobStateList":
                        list = "";
                        foreach (DataGridViewColumn dc in dgQueue.Columns)
                        {
                            if (!dc.Visible) continue;
                            list = list + dc.Name + ":" + dc.DisplayIndex.ToString()+ ",";
                        }
                        if (list.Length > 0) list = list.Substring(0, list.Length - 1);
                        nodeValue.InnerXml = list;
                        break;

                    case "MsgTypeList":
                        list = "";
                        foreach (DataGridViewRow dr in dgQueue.Rows)
                        {
                            if (!dr.Visible) continue;
                            list = list + dr.Cells["MessageType"].Value.ToString() + ":" + dr.Cells["SortOrder"].Value.ToString() + ",";
                        }
                        if (list.Length > 0) list = list.Substring(0, list.Length - 1);
                        nodeValue.InnerXml = list;
                        break;
                }
            }
            xmlConfig.Save(configFile);
        }
        #endregion
    }
}